一个轻量级分布式 RPC 框架 上
RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样。
具体的介绍就不多说了,通过搜索引擎可以获得很多这方面的介绍。
这里推荐一篇文章:https://my.oschina.net/huangyong/blog/361751
对于架构的设计,说些自己的看法,不想去说那么抽象,拿一个人来讲:
首先,人体的组成必须要由骨架,这就是表示项目应该有一个总体的架构图。
然后,要有各个器官来各司其职,这就是各个模块了。
再者,各个器官之间要交流,那就需要有个中间件来承载的,这里就是血管,而血液就是信息承载体,里面包含了各种器官需要的物质和生产出的物 质,血液在代码中的体现可能是一个ConcurrentMap
。
最后,专注于各个模块的实现,所用的逻辑和技术具体问题具体再分析处理
首先对此框架的设计图:
图1
本文将为您揭晓开发轻量级分布式 RPC
框架的具体过程,该框架基于 TCP
协议,提供了NIO
特性,提供高效的序列化方式,同时也具备服务注册与发现的能力。
根据以上技术需求,我们可使用如下技术选型:
Spring
: 它是最强大的依赖注入框架,也是业界的权威标准。Netty
: 它使NIO
编程更加容易,屏蔽了 Java 底层的 NIO 细节。Kryo
: 一个快速高效的Java序列化框架,旨在提供快速、高效和易用的API。无论文件、数据库或网络数据Kryo都可以随时完成序列化ZooKeeper
: 提供服务注册与发现功能,开发分布式系统的必备选择,同时它也具备天生的集群能力。
Netty 请自己找文章或书学习的,推荐Netty.in.Action
编写核心模块
一个模块下面也是可以根据很多细分的小模块流程来做的
1,编写通用模块
因为用的是netty,所以对于netty的编程主要考虑几个方面,编解码处理,核心逻辑处理类。编解码处理就涉及到了序列化处理和所要处理的对象,
我们所要请求的包括方法的名称参数和方法所属类,设计上,以一个id为唯一标志,服务端处理完返回的结果同样携带此id,这样就可以很轻松取到了,
这也就是血液所携带的信息的体现。
设计请求和回复类:
1 | package com.nia.rpc.core.protocol; |
1 | package com.nia.rpc.core.protocol; |
关于lombok
,请看通过Lombok来简化你的代码
序列化处理类
先创建一个接口,方便以后有其他序列化实现,这里仅使用Kryo
1 | package com.nia.rpc.core.serializer; |
具体实现步骤很简单,如下代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34package com.nia.rpc.core.serializer;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
/**
* Author 知秋
* Created by Auser on 2017/2/17.
*/
public class KryoSerializer implements Serializer {
public byte[] serialize(Object obj) {
Kryo kryo=new Kryo();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Output output = new Output(byteArrayOutputStream);
kryo.writeClassAndObject(output,obj);
output.close();
return byteArrayOutputStream.toByteArray();
}
public <T> T deserialize(byte[] bytes) {
Kryo kryo=new Kryo();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
Input input = new Input(byteArrayInputStream);
input.close();
return (T) kryo.readClassAndObject(input);
}
}
编解码处理类
编码处理:
1 | package com.nia.rpc.core.protocol; |
解码处理
注意点请看注释,都是一贯套路 具体关于此类的文档总结:netty 数据分包、组包、粘包处理机制(部分).md)
1 | package com.nia.rpc.core.protocol; |
2,编写服务端模块
首先搞定ip和端口的获取
1 | package com.nia.rpc.core.utils; |
服务端对客户端过来方法请求 的处理逻辑:
此处的service代码里已经解释过,就是服务端所注册的接口(其实也不一定是接口,对外可能是restful的一个地址)的实现类
1 | package com.nia.rpc.core.server; |
定义服务接口:
1 | package com.nia.rpc.core.server; |
服务端主逻辑的实现:
通过Curator来操作zookeeper的节点,具体的使用请看跟着实例学习ZooKeeper的用法
服务端起起来,具体看下面
start()
代码,都是netty
的格式化用法,将之前的准备应用到此然后调用
registerService()
方面实现注册逻辑: 获取所连接
zk
地址; 获取服务端本地
ip
; 通过
Curator
创建一个zk
的客户端; 添加注册基础服务节点 ;
关停相关服务的逻辑
,具体看下面源码:
1 | package com.nia.rpc.core.server; |
暂时先到此,接下来的内容请看下篇